﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using FinanSoft.Entities;
using FinanSoft.Utilities;

namespace FinanSoft.DataLayer
{
    class ReportDataManager
    {

        #region Singleton

        private ReportDataManager()
        { }

        /// <summary>
        /// Única instancia de esta clase
        /// </summary>
        private static ReportDataManager _instance;

        /// <summary>
        /// Método para implementar el patrón de Singleton
        /// </summary>
        /// <returns>Instancia única de la clase</returns>
        public static ReportDataManager GetInstance()
        {
            if (_instance == null)
                _instance = new ReportDataManager();
            return _instance;
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Funcion que se encarga de modificar los datos de una compañia
        /// </summary>
        /// <param name="Temporada">Recibe un objeto de Compañía a modificar</param>
        /// <returns>retorna exito si es actualizado con exito</returns>
        public bool ModifyCompany(Company company)
        {
            try
            {
                AppConfigReader appConfig = AppConfigReader.GetInstance();
                string spName = Constants.SP_NAME_MOD_COMPANY;
                SqlParameter[] parameters = {
                new SqlParameter(Constants.SP_PARAM_MOD_ID_LEGAL, int.Parse(company.LegalId)),
                new SqlParameter(Constants.SP_PARAM_MOD_NAME_COMPANY, company.Name),
                new SqlParameter(Constants.SP_PARAM_MOD_PHONE, int.Parse(company.Phone)),
                new SqlParameter(Constants.SP_PARAM_MOD_FAX, int.Parse(company.Fax)),
                new SqlParameter(Constants.SP_PARAM_MOD_DIV_PERCENTAGE, company.DividendPercentage),
                new SqlParameter(Constants.SP_PARAM_MOD_TAX_PERCENTAGE, company.TaxPercentage)};

                SqlDataHelper dataHelper = new SqlDataHelper(appConfig.GetConnectionString(Constants.DB_CONN));

                SqlDataReader result = dataHelper.ExecuteStoredProcedure(spName, parameters);

                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// Funcion que se encarga de insertar una nueva compañía junto con un usuario en la base de datos
        /// </summary>
        /// <param name="company">Información de la compañía que se quiere insertar</param>
        /// <param name="administrator">Información del usuario administrador de la compañía</param>
        /// <returns>Indica si se pudo registrar la compañía exitosamente o no</returns>
        public bool CreateCompany(Company company, User administrator, String password)
        {
            try
            {
                AppConfigReader appConfig = AppConfigReader.GetInstance();
                string spName = Constants.SP_NAME_CREATE_COMPANY;
                SqlParameter[] parameters = {
                    new SqlParameter(Constants.SP_PARAM_CREATE_COMPANY_LEGAL_ID, int.Parse(company.LegalId)),
                    new SqlParameter(Constants.SP_PARAM_CREATE_COMPANY_COMPANY_NAME, company.Name),
                    new SqlParameter(Constants.SP_PARAM_CREATE_COMPANY_PHONE, int.Parse(company.Phone)),
                    new SqlParameter(Constants.SP_PARAM_CREATE_COMPANY_FAX, int.Parse(company.Fax)),
                    new SqlParameter(Constants.SP_PARAM_CREATE_COMPANY_LOGO, company.Logo),
                    new SqlParameter(Constants.SP_PARAM_CREATE_COMPANY_ADMIN_NAME, administrator.Nombre),
                    new SqlParameter(Constants.SP_PARAM_CREATE_COMPANY_USERNAME, administrator.NombreUsuario),
                    new SqlParameter(Constants.SP_PARAM_CREATE_COMPANY_PASSWORD, password),
                    new SqlParameter(Constants.SP_PARAM_CREATE_COMPANY_DIV_PERCENTAGE, company.DividendPercentage),
                    new SqlParameter(Constants.SP_PARAM_CREATE_COMPANY_TAX_PERCENTAGE, company.TaxPercentage)};

                SqlDataHelper dataHelper = new SqlDataHelper(appConfig.GetConnectionString(Constants.DB_CONN));

                SqlDataReader result = dataHelper.ExecuteStoredProcedure(spName, parameters);

                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// Obtiene la información de la compañía dueña de la base de datos
        /// </summary>
        /// <returns>Información de la compañía</returns>
        public Company GetCompanyInfo()
        {
            try
            {
                AppConfigReader appConfig = AppConfigReader.GetInstance();
                string spName = Constants.SP_NAME_GET_COMPANY_INFO;
                SqlParameter[] parameters = new SqlParameter[0];
                SqlDataHelper dataHelper = new SqlDataHelper(appConfig.GetConnectionString(Constants.DB_CONN));
                SqlDataReader result = dataHelper.ExecuteStoredProcedure(spName, parameters);
                result.Read();
                String name = result[Constants.SP_COLUMN_GET_COMPANY_INFO_NAME].ToString();
                String fax = result[Constants.SP_COLUMN_GET_COMPANY_INFO_FAX].ToString();
                String phone = result[Constants.SP_COLUMN_GET_COMPANY_INFO_PHONE].ToString();
                String legalId = result[Constants.SP_COLUMN_GET_COMPANY_INFO_LEGAL_ID].ToString();
                //ToDo: Cambiar esto por una imagen
                Byte[] logo = (Byte[]) result[Constants.SP_COLUMN_GET_COMPANY_INFO_LOGO];
                double dividendPercentage = Convert.ToDouble(result[Constants.SP_COLUMN_GET_COMPANY_INFO_DIV_PERCENTAGE]);
                double taxPercentage = Convert.ToDouble(result[Constants.SP_COLUMN_GET_COMPANY_INFO_TAX_PERCENTAGE]);
                dataHelper.CloseReader();
                return new Company(name, legalId, phone, fax, logo, dividendPercentage, taxPercentage);
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        /// <summary>
        /// Obtiene el saldo de todas las cuentas para una temporada en específico
        /// </summary>
        /// <param name="seasonId">Id de la temporada que se solicita</param>
        /// <param name="currencyId">Id de la moneda para la que se quiere el saldo. Puede ser local o del sistema</param>
        /// <returns>Arreglo con el reporte del saldo de cada cuenta de la temporada</returns>
        public List<AccountBalanceReport> GetSeasonAccountBalances(int seasonId, int currencyId)
        {
            try
            {
                AppConfigReader appConfig = AppConfigReader.GetInstance();
                string spName = Constants.SP_NAME_GET_SEASON_BALANCES;
                SqlParameter[] parameters = new SqlParameter[2];
                parameters[0] = new SqlParameter(Constants.SP_PARAM_GET_SEASON_BALANCES_SEASON_ID, seasonId);
                parameters[1] = new SqlParameter(Constants.SP_PARAM_GET_SEASON_BALANCES_CURRENCY_ID, currencyId);
                SqlDataHelper dataHelper = new SqlDataHelper(appConfig.GetConnectionString(Constants.DB_CONN));
                SqlDataReader result = dataHelper.ExecuteStoredProcedure(spName, parameters);
                List<AccountBalanceReport> reports = 
                    buildReports(result,
                        Constants.SP_COLUMN_GET_SEASON_BALANCES_ACCOUNT_ID,
                        Constants.SP_COLUMN_GET_SEASON_BALANCES_BALANCE,
                        Constants.SP_COLUMN_GET_SEASON_BALANCES_INCREMENT_TYPE);
                dataHelper.CloseReader();
                return reports;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        /// <summary>
        /// Obtiene el saldo de todas las cuentas para un periodo contable en específico
        /// </summary>
        /// <param name="seasonId">Id del periodo contable que se solicita</param>
        /// <param name="currencyId">Id de la moneda para la que se quiere el saldo. Puede ser local o del sistema</param>
        /// <returns>Arreglo con el reporte del saldo de cada cuenta del periodo contable</returns>
        public List<AccountBalanceReport> GetPeriodAccountBalances(int periodId, int currencyId)
        {
            try
            {
                AppConfigReader appConfig = AppConfigReader.GetInstance();
                string spName = Constants.SP_NAME_GET_PERIOD_BALANCES;
                SqlParameter[] parameters = new SqlParameter[2];
                parameters[0] = new SqlParameter(Constants.SP_PARAM_GET_PERIOD_BALANCES_PERIOD_ID, periodId);
                parameters[1] = new SqlParameter(Constants.SP_PARAM_GET_PERIOD_BALANCES_CURRENCY_ID, currencyId);
                SqlDataHelper dataHelper = new SqlDataHelper(appConfig.GetConnectionString(Constants.DB_CONN));
                SqlDataReader result = dataHelper.ExecuteStoredProcedure(spName, parameters);
                List<AccountBalanceReport> reports =
                    buildReports(result,
                        Constants.SP_COLUMN_GET_PERIOD_BALANCES_ACCOUNT_ID,
                        Constants.SP_COLUMN_GET_PERIOD_BALANCES_BALANCE,
                        Constants.SP_COLUMN_GET_PERIOD_BALANCES_INCREMENT_TYPE);
                dataHelper.CloseReader();
                return reports;
            }
            catch (Exception ex)
            {
                return null;
            }
        }
        #endregion

        #region Private/Protected Methods
        /// <summary>
        /// Arma los reportes de los saldos de las cuentas con el resultado de SP brindado y con el nombre
        /// de las columnas que posee el resultado
        /// </summary>
        /// <param name="result">Resultado de la base de datos con los saldos de cuenta</param>
        /// <param name="accountName">Nombre de la columna con el id de la cuenta</param>
        /// <param name="balanceName">Nombre de la columna con el saldo de la cuenta</param>
        /// <param name="alDebeName">Nombre de la columna que dice el tipo de incremento del saldo (Debe o Haber)</param>
        /// <returns></returns>
        private List<AccountBalanceReport> buildReports(SqlDataReader result, String accountName, String balanceName, String alDebeName)
        {
            List<AccountBalanceReport> balanceList = new List<AccountBalanceReport>();
            while (result.Read())
            {
                int accountId = Convert.ToInt32(result[accountName]);
                double balance = Convert.ToDouble(result[balanceName]);
                bool alDebe = Convert.ToBoolean(result[alDebeName]);
                balanceList.Add(new AccountBalanceReport(accountId, balance, alDebe));

            }
            return balanceList;
        }
        #endregion


    }
}
